/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package holdem.network;

import holdem.Card;
import holdem.CardComparator;
import holdem.Deck;
import holdem.Player;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.HashMap;
import java.util.Map;

/**
 *
 * @author Anders
 */
public class PokerDealer implements MessageReceiverInCommunicationModule{

    private int turn = -1, checkAmount = 0, dealer = 0, tabelMoney = 0;
    private List<Card> cardTabel = new ArrayList<Card>();
    private Deck deck;
    private Card hands[][];
    private boolean checkRound = false;
    

    private int turn()
    {
        if((turn + dealer) < Server.users.size())
            return turn + dealer;
        else
            return (turn + dealer) - Server.users.size();
    }
    
    private void flip() throws IOException
    {
        for (ClientHandler i : Server.users)
        {
            tabelMoney += i.player.moneyBet;
            i.player.moneyAtCurrent -= i.player.moneyBet;
            i.player.moneyBet = 0;
        }

        checkAmount = 0;

        //Send out the new card to everyone
        if(cardTabel.size() == 5)
        {
            whowin();
            return;
        }
        //Take a card and put it on the tabel.
        Card tmp = deck.take();
        Server.broadcastFromServer(new DealTableCardEvent(tmp));
        cardTabel.add(tmp);
        
    }
    public void startGame() throws IOException
    {
        //give all players chairs
        turn = 0;
        tabelMoney = 0;
        cardTabel.clear();
        deck = new Deck();
        Server.broadcastFromServer(new GameStartEvent());
        
        for(int i = 0; i < Server.users.size(); i++)
        {
            Player tmp = Server.users.get(i).player;
            Server.broadcastFromServer(new PlayerJoinEvent(i, tmp.getMoneyAtCurrent(), tmp.getName()));
        }
        Server.broadcastFromServer(new DealerChangeEvent(dealer));
        blinds();
        //newgame();
    }
    
    private void blinds() throws IOException
    {
        int big = 10, small = 5;
        Server.broadcastFromServer(new SmallBlindIncreaseEvent(turn(), small));
        Server.users.get(turn()).player.moneyBet = small;
        turn = 1;
        Server.broadcastFromServer(new BigBlindIncreaseEvent(turn(), big));
        Server.users.get(turn()).player.moneyBet = big;

        checkAmount = big;
        turn = 2;
        //tabelMoney += 10 + 5;
        nextplayer();
    }

    public void nextplayer() throws IOException
    {
        if (Server.users.size() <= turn)
        {
            //Check event
            if (!checkRound)
                checkRound = true;
            else
            {
                checkRound = false;
                //for(ClientHandler i : Server.users)
                    //i.player.moneyBet = 0;

                if(cardTabel.isEmpty())
                    newgame();
                else
                    flip();
            }

            turn = 0;
            //Have to adjust this later
        }

        ClientHandler c = Server.users.get(turn());
        if (c != null)
        {
            //If palyer is folded and dont have to check.

            // IMPORTANT to change
            if(c.player.isFolded || checkRound && c.player.moneyBet == checkAmount || c.player.hasQuit)
            {
                changeplayer();
                return;
            }

            Server.broadcastFromServer(new ChangeTurnEvent(turn()));
            //Witch player turn it is start timer her
            //if req recivde
        }
    }

    public void newgame() throws IOException
    {
        turn = 0;
        //Flips 3 cards to the tabel
        for(int i = 0; i < 3; i++)
            flip();

        //Give cards to all players.
        
        Card tmp[][] = new Card[Server.users.size()][2];
        for(int i = 0; i < 2; i++)
            for(int j = 0; j < Server.users.size(); j++)
                tmp[j][i] = deck.take();

        //Send hand to rigth player
        for(int i = 0; i < Server.users.size(); i++)
            Server.users.get(i).sendMessage(new DealHandCardEvent(i, tmp[i]));

        //Save all hands in for later use.
        hands = tmp;
        //statr blind round

        nextplayer();
    }
    public void showdown() 
    {
        //show all cards
        Map<Integer, List <Card>> mp = new HashMap<Integer, List <Card>>();

        for(int i = 0; i < hands.length; i++)
        {
            List<Card> tmp = new ArrayList<Card>();

            for(int j = 0; j < hands[i].length; j++)
                tmp.add(hands[i][j]);

            mp.put(i, tmp);
        }

        Server.broadcastFromServer(new RevealPlayerHandEvent(mp));
    }
    public void whowin() throws IOException
    {
        showdown();
        try
        {
            Thread.sleep(2000);
        }
        catch (InterruptedException ex)
        {
            Logger.getLogger(PokerDealer.class.getName()).log(Level.SEVERE, null, ex);
        }
        //Update all players money.
        havebestcard();
        for(int i = 0; i < Server.users.size(); i++)
        {
            //Server.broadcastFromServer(new MoneyGainEvent(i, 100));
        }
        //havebestcard()
        Server.broadcastFromServer(new GameEndEvent());


        //Change dealer for next game
        if(dealer == Server.users.size())
            dealer = 0;
        else
            dealer++;

        //Start next round
        startGame();
    }

    public void havebestcard()
    {
        //coompare all players hands and se how wins the game
        Integer [] tmp = CardComparator.compare(cardTabel.toArray(new Card[]{}), hands);
        for(int i : tmp)
        {
            Server.broadcastFromServer(new MoneyGainEvent(i, tabelMoney/tmp.length));
            Server.users.get(i).player.moneyAtCurrent += tabelMoney/tmp.length;
        }
        
    }

    private void changeplayer() throws IOException
    {
        turn++;
        nextplayer();
    }
    
    
    public void bet(Integer amount, int playerID)
    {
        if(playerID == turn()  && amount > checkAmount && !checkRound)
        {
            System.out.println("Bet " + amount);
            Server.broadcastFromServer(new BetEvent(playerID, amount));
            checkAmount = amount;
            //Server.users.get(playerID).player.betMoney(amount);
            Server.users.get(playerID).player.moneyBet = amount;
            try
            {
                changeplayer();
            }
            catch (IOException ex)
            {
                Logger.getLogger(PokerDealer.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public void raise(Integer amount, int playerID)
    {
        if(playerID == turn() && amount > checkAmount && !checkRound)
        {
            System.out.println("Raise " + amount);
            Server.broadcastFromServer(new RaiseEvent(playerID, amount));
            //Server.users.get(playerID).player.betMoney(amount);
            checkAmount = amount;
            Server.users.get(playerID).player.moneyBet = amount;
            try
            {
                changeplayer();
            }
            catch (IOException ex)
            {
                Logger.getLogger(PokerDealer.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public void fold(int playerID)
    {
        if(playerID == turn())
        {
            System.out.println("Fold " + playerID);
            Server.users.get(playerID).player.fold();
            Server.broadcastFromServer(new FoldEvent(playerID));
            try
            {
                changeplayer();
            } catch (IOException ex)
            {
                Logger.getLogger(PokerDealer.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public void check(int playerID)
    {
        if(turn() == playerID)
        {
            System.out.println("Check " + playerID);
            //Server.users.get(playerID).player.betMoney(checkAmount);
            Server.users.get(playerID).player.moneyBet = checkAmount;
            //So mutch
            Server.broadcastFromServer(new CheckEvent(playerID));
            try
            {
                changeplayer();
            } catch (IOException ex)
            {
                Logger.getLogger(PokerDealer.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public void quit(int playerID)
    {
        System.out.println("Quit " + playerID);
        Server.users.get(playerID).player.hasQuit = true;
        Server.broadcastFromServer(new UserQuit(playerID));
    }

    public void letMeJoin(String playerName, Integer money, int playerID)
    {
        System.out.println("Join " + playerName);
        Server.users.get(playerID).player = new Player(playerName, playerID, money);
        try
        {
            Server.users.get(playerID).sendMessage(new PlayerJoinAccepted(playerID));
        } catch (IOException ex)
        {
            Logger.getLogger(PokerDealer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public int getTurn()
    {
        return turn;
    }

    public void start()
    {
        if(turn < 0)
            try
            {
                startGame();
            }
            catch (IOException ex)
            {
                Logger.getLogger(PokerDealer.class.getName()).log(Level.SEVERE, null, ex);
            }
    }

    public void call(int playerID)
    {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}